package ev.ftw.dna;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

import ev.ftw.gff.FragConocido;
import ev.ftw.gff.GFFFileIO;

/**
 * Clase que encapsula el trabajo con el ADN de Sacharomyces Pombe
 * 
 * @date 01.08.2012
 * @author Enrique Vázquez de Luis
 */
public class DNA_Schizosaccharomyces_pombe {

	/**
	 * Conjunto de cromosomas
	 */
	Cromosoma cromosomas[];
	
	/**
	 * Constructor sin parámetros, reserva memoria para los 6 cromosomas.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	public DNA_Schizosaccharomyces_pombe(){
		cromosomas = new Cromosoma[6];
	}
	
	/**
	 * Contructor con un parámetro que reserva memoria para los cromosomas y los rellena
	 * leyendo los datos de un fichero.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param fichero Ruta al fichero WIG donde están los datos
	 */
	public DNA_Schizosaccharomyces_pombe(String fichero){
		cromosomas = new Cromosoma[6];
		
		ArrayList<Sonda> sondas;
		String aux;
		String paraParsear[];
		
		String tipo;
		String nombre;
		boolean pasoVariable;
		String cromosoma;
		int span;
		char direccion;
		
		float auxf;
		try {
			Scanner s = new Scanner(new File(fichero));
			
			aux = s.next();
			if(aux.compareToIgnoreCase("track") != 0) return;
			
			for(int i = 0; i < 6 && s.hasNext(); i++){
				sondas = new ArrayList<Sonda>();
				
				aux = s.next();
				paraParsear = aux.split("=");
				tipo = paraParsear[1];
				aux = s.next();
				paraParsear = aux.split("=");
				nombre = paraParsear[1];
				if(i%2 == 0) direccion = '+';
				else if(i%2 != 0) direccion = '-';
				else direccion = '.';
				aux = s.next();
				if(aux.compareToIgnoreCase("variableStep") == 0) pasoVariable = true;
				else pasoVariable = false;
				aux = s.next();
				paraParsear = aux.split("=");
				cromosoma = paraParsear[1];
				aux = s.next();
				paraParsear = aux.split("=");
				span = Integer.parseInt(paraParsear[1]);
				aux = s.next();
				
				while(aux.compareToIgnoreCase("track") != 0){
					auxf = Float.parseFloat(s.next());
					sondas.add(new Sonda(span, Integer.parseInt(aux), auxf));
					if(!s.hasNext())break;
					aux = s.next();
				}
				this.cromosomas[i] = new Cromosoma(tipo, nombre, pasoVariable, cromosoma, span, direccion, sondas);
				//System.out.println(this.cromosomas[i].getResolucion());
			}
			
			
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}catch (java.util.NoSuchElementException e){
			e.printStackTrace();
		} catch (Exception e){
			e.printStackTrace();
		}
		
	}
	
	/**
	 * Función que aplica el filtro de ancho de banda a todos los cromosomas. <br>
	 * Lo hace simultáneamente gracias al uso de hilos.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param tam Ancho del filtro a cada lado (tamaño real tam*2 + 1).
	 */
	public void bandwith(int tam){
		HiloExp hilos[] = new HiloExp[6];
		for(int i = 0; i < 6; i++){
			hilos[i] = new HiloExp(this.cromosomas[i], HiloExp.BANDWITH);
			hilos[i].setArg0(tam);
			hilos[i].start();
		}
		
		for(int i = 0; i < 6; i++){
			try {
				hilos[i].join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Función que aplica el filtro de wavelet a todos los cromosomas. <br>
	 * Lo aplica simultáneamente gracias al uso de hilos.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param limite Límite del salto en el espacio de Hilbert para anularlo con el filtro.
	 */
	public void filtroWLT(float limite){
		HiloExp hilos[] = new HiloExp[6];
		for(int i = 0; i < 6; i++){
			hilos[i] = new HiloExp(this.cromosomas[i], HiloExp.FILTRO_WAVELET);
			hilos[i].setLimiteWLT(limite);
			hilos[i].start();
		}
		
		for(int i = 0; i < 6; i++){
			try {
				hilos[i].join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Función que amplia la resolución un número determinado de veces en todo el cromosoma. <br>
	 * Lo hace simultáneamente gracias al uso de hilos.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param cantidad Cantidad por la que aumentará la resolución.
	 */
	public void ampliarResolucion(int cantidad){
		HiloExp hilos[] = new HiloExp[6];
		for(int i = 0; i < 6; i++){
			hilos[i] = new HiloExp(this.cromosomas[i], HiloExp.AUMENTA_RESOLUCION);
			hilos[i].setArg0(cantidad);
			hilos[i].start();
		}
		
		for(int i = 0; i < 6; i++){
			try {
				hilos[i].join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Función que reduce la resolución un valor determinado. <br>
	 * Lo hace simultáneamente gracias al uso de hilos.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis 
	 * @param cantidad Cantidad en que debe reducirse la resolución.
	 */
	public void reducirResolucion(int cantidad){
		HiloExp hilos[] = new HiloExp[6];
		for(int i = 0; i < 6; i++){
			hilos[i] = new HiloExp(this.cromosomas[i], HiloExp.REDUCE_RESOLUCION);
			hilos[i].setArg0(cantidad);
			hilos[i].start();
		}
		
		for(int i = 0; i < 6; i++){
			try {
				hilos[i].join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Función que opera el genoma actual con otro pasado por parámetro.<br>
	 * Lo hace simultáneamente gracias al uso de hilos.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param operacion Operación a realizar.
	 * @param operando2 Genoma con el que operar.
	 */
	public void opera(int operacion, DNA_Schizosaccharomyces_pombe operando2){
		HiloExp hilos[] = new HiloExp[6];
		for(int i = 0; i < 6; i++){
			hilos[i] = new HiloExp(this.cromosomas[i], operando2.getCromosomas()[i], operacion);
			hilos[i].start();
		}
		
		for(int i = 0; i < 6; i++){
			try {
				hilos[i].join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Función que opera el genoma actual con un número pasado como parámetro. <br>
	 * Lo hace simultáneamente gracias al uso de hilos.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param operacion Operación a realizar.
	 * @param operando2 Número con el que operar.
	 */
	public void opera(int operacion, float operando2){
		HiloExp hilos[] = new HiloExp[6];
		for(int i = 0; i < 6; i++){
			hilos[i] = new HiloExp(this.cromosomas[i], operacion);
			hilos[i].setLimiteMedia(operando2);
			hilos[i].start();
		}
		
		for(int i = 0; i < 6; i++){
			try {
				hilos[i].join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Función que elimina los errores más reconocibles de los cromosomas. <br>
	 * Lo hace simultáneamente gracias al uso de hilos.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param tam Tamaño del ancho de banda de búsqueda de errores.
	 */
	public void eliminaErrores(int tam){
		HiloExp hilos[] = new HiloExp[6];
		for(int i = 0; i < 6; i++){
			hilos[i] = new HiloExp(this.cromosomas[i], HiloExp.ELIMINA_ERRORES);
			hilos[i].setArg0(tam);
			hilos[i].start();
		}
		
		for(int i = 0; i < 6; i++){
			try {
				hilos[i].join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Función que guarda en un fichero .gff los fragmentos de ADN expresados, encontrados mediante la búsqueda
	 * por wavelet. <br>
	 * Lo hace simultáneamente gracias al uso de hilos.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param umbralWLT Umbral de tamaño en el espacio de Hilbert para localizar un salto.
	 * @param umbralMedia Umbral de la media para reconocer la expresión.
	 * @param fichero Fichero en que se guardarán los fragmentos encontrados.
	 */
	public void expresionWLT(float umbralWLT, float umbralMedia, String fichero){
		HiloExp hilos[] = new HiloExp[6];
		for(int i = 0; i < 6; i++){
			hilos[i] = new HiloExp(this.cromosomas[i], HiloExp.BUSCA_EXPRESION_WLT);
			hilos[i].setLimiteWLT(umbralWLT);
			hilos[i].setLimiteMedia(umbralMedia);
			hilos[i].start();
		}
		
		int tam = 0;
		for(int i = 0; i < 6; i++){
			try {
				hilos[i].join();
				tam += hilos[i].getFragmentos().length;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		FragConocido[] fragmentos = new FragConocido[tam];
		int offset = 0;
		for(int i = 0; i < 6; i++){
			System.arraycopy(hilos[i].getFragmentos(), 0, fragmentos, offset, hilos[i].getFragmentos().length);
			offset += hilos[i].getFragmentos().length;
		}
		
		String [] cadenas = new String[4];
		cadenas[0] = "##gff-version 3";
		cadenas[1] = "##sequence-region chromosome1 1 5579133";
		cadenas[2] = "#sequence-region chromosome2 1 4539804";
		cadenas[3] = "##sequence-region chromosome3 1 2452883";
		GFFFileIO.escribeEnFichero(fichero, fragmentos, cadenas);
	}
	
	/**
	 * Función que guarda en un fichero .gff la información de los fragmentos expresados encontrados gracias al
	 * algoritmo de la media. <br>
	 * Lo hace simultáneamente gracias al uso de hilos.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param umbral Umbral para la búsqueda de expresión.
	 * @param fichero Ruta al fichero donde guardar los fragmentos.
	 */
	public void expresionSencilla(float umbral, String fichero){
		HiloExp hilos[] = new HiloExp[6];
		for(int i = 0; i < 6; i++){
			hilos[i] = new HiloExp(this.cromosomas[i], HiloExp.BUSCA_EXPRESION_MEDIA);
			hilos[i].setLimiteMedia(umbral);
			hilos[i].start();
		}
		
		int tam = 0;
		for(int i = 0; i < 6; i++){
			try {
				hilos[i].join();
				tam += hilos[i].getFragmentos().length;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		FragConocido[] fragmentos = new FragConocido[tam];
		int offset = 0;
		for(int i = 0; i < 6; i++){
			System.arraycopy(hilos[i].getFragmentos(), 0, fragmentos, offset, hilos[i].getFragmentos().length);
			offset += hilos[i].getFragmentos().length;
		}
		
		String [] cadenas = new String[4];
		cadenas[0] = "##gff-version 3";
		cadenas[1] = "##sequence-region chromosome1 1 5579133";
		cadenas[2] = "#sequence-region chromosome2 1 4539804";
		cadenas[3] = "##sequence-region chromosome3 1 2452883";
		GFFFileIO.escribeEnFichero(fichero, fragmentos, cadenas);
	}
	
	/**
	 * Función que imprime en un fichero .WIG el genoma actual completo.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param fichero Fichero WIG donde guardar el genoma.
	 */
	public void printFile(String fichero){
		try {
			PrintWriter p = new PrintWriter(new File(fichero));
			for(int i = 0; i < cromosomas.length; i++){
				cromosomas[i].printFileCompleto(p);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	public Cromosoma[] getCromosomas(){
		return this.cromosomas;
	}
	
}
